package com.xbongbong.saas.service.toolbox.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.enums.SheetTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.errorcodes.PaymentErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.sheet.pojo.SheetAttrPojo;
import com.xbongbong.saas.analytical.impl.PayPlanSheetValidateAnalyticalServiceImpl;
import com.xbongbong.saas.analytical.impl.PaymentSheetValidateAnalyticalServiceImpl;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.PaySheetEnum;
import com.xbongbong.saas.enums.business.PaymentSheetDistributorEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.help.SaveFormatHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getJsonArrFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getJsonArrOrDefaultFromFormData;
import static java.lang.String.format;

@Component
public class SaasSaveHelper {

    private static final Logger LOG = LoggerFactory.getLogger(SaasSaveHelper.class);

    @Resource
    private FundHelp fundHelp;
    @Resource
    private PaymentSheetValidateAnalyticalServiceImpl paymentSheetAnalyticalService;
    @Resource
    private PayPlanSheetValidateAnalyticalServiceImpl payPlanSheetAnalyticalService;

    /**
     * 得到amountDetail，并校验金额，目前只有回/款单和(进项)发票有该金额明细
     * @param dataId 数据id，如果为null或0则校验金额0的情况，否则不校验（编辑时红冲金额为负数，肯定小于0）
     * @param sheetTypeEnum 回/付款单类型总枚举
     * @param dataList 数据data
     * @param otherBusinessType 如果是发票、进项发票，则sheetTypeEnum也是UNKNOWN，因此通过该参数来判断是否是发票
     * @return com.alibaba.fastjson.JSONArray
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    public JSONArray getAmountDetail4Check(Long dataId, SheetTypeEnum sheetTypeEnum, JSONObject dataList,Integer otherBusinessType) throws XbbException {
        //销项发票、进项发票标记
        boolean invoiceFlag = Objects.equals(otherBusinessType, XbbRefTypeEnum.INVOICE.getCode()) || Objects.equals(otherBusinessType, XbbRefTypeEnum.PURCHASE_INVOICE.getCode());
        //回款单、付款单标记
        boolean payFlag = SheetTypeEnum.validatePay(sheetTypeEnum);
        if (!invoiceFlag && !payFlag) {
            //不是发票/进项发票，也不是回/付款单，则直接返回null
            return null;
        }
        //发票、进项发票、回款单、付款单中金额明细
        JSONArray amountDetail = getJsonArrOrDefaultFromFormData(dataList, PaasConstant.AMOUNTDETAIL, new JSONArray());
        //回/付款单的amountDetail需要校验金额等，发票/进项发票明细不用处理校验金额，直接返回
        if (invoiceFlag || CollectionsUtil.isEmpty(amountDetail)) {
            return amountDetail;
        }
        //只有新增的数据需要校验
        boolean flag = Objects.equals(dataId, null) || Objects.equals(dataId, BasicConstant.ZERO_LONG);
        if (flag) {
            checkSheetAmount(sheetTypeEnum, dataList);
        }
        //初始化字段attr
        SheetAttrPojo sheetAttrPojo = new SheetAttrPojo(sheetTypeEnum.getXbbRefTypeEnum());
        if (amountDetail.size() > BasicConstant.ONE) {
            //回款單明細则移除填了0的数据，且要把移除数据关联的合同、回款、签订人从dataList内也去掉
            Iterator<Object> iterator = amountDetail.iterator();
            //明细内有金额的合同、应收款、归属人
            List<Long> detailContractIds = new ArrayList<>();
            List<String> detailContractNos = new ArrayList<>();
            List<Long> detailPaymentIds = new ArrayList<>();
            List<String> detailPaymentNos = new ArrayList<>();
            //外部归属人必须只能是明细内有金额的归属人，且要排重
            Set<Object> detailSignPerson = new HashSet<>();
            while (iterator.hasNext()) {
                Object object = iterator.next();
                JSONObject jsonObject = (JSONObject)object;
                Double amount = jsonObject.getDouble(sheetAttrPojo.getAttrAmount());
                if(amount == null || amount == 0D) {
                    iterator.remove();
                } else {
                    //处理归属人
                    List<Object> signUserIds = ProSaveHelp.getIdList(jsonObject.getJSONArray(sheetAttrPojo.getAttrBelongId()));
                    detailSignPerson.addAll(signUserIds);
                    //处理合同，拼到父回款的detailContractIds、detailContractNos上
                    handleDetailIdName(jsonObject, sheetAttrPojo.getAttrCon(), detailContractIds, detailContractNos);
                    //处理回款，拼到父回款的detailPaymentIds、detailPaymentNos上
                    handleDetailIdName(jsonObject, sheetAttrPojo.getAttrPlan(), detailPaymentIds, detailPaymentNos);
                }
            }
            dataList.put(sheetAttrPojo.getAttrCon(), detailContractIds);
            dataList.put(sheetAttrPojo.getAttrConLink(), detailContractNos);
            dataList.put(sheetAttrPojo.getAttrPlan(), detailPaymentIds);
            dataList.put(sheetAttrPojo.getAttrPlanLink(), detailPaymentNos);
            dataList.put(sheetAttrPojo.getAttrBelongId(), detailSignPerson);
            return amountDetail;
        }
        //新增的数据，且不是预收/付款也不是红冲预收/付款余额类型，则需要校验归属人
        boolean checkBelong = flag && !SheetTypeEnum.noBelong(sheetTypeEnum);
        if (checkBelong) {
            //处理归属人
            JSONArray signUserArr = dataList.getJSONArray(sheetAttrPojo.getAttrBelongId());
            if (signUserArr == null || signUserArr.size() == 0) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NO_BELONG_AMOUNT_DETAIL);
            } else if (signUserArr.size() > 1) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208047, format(PaymentErrorCodeEnum.API_ERROR_208047.getMsg(), sheetTypeEnum.getXbbRefTypeEnum().getName()));
            }
        }
        return null;
    }

    /**
     * 校验回/付款单金额
     * @param sheetTypeEnum 回/付款单类型
     * @param dataList 回/付款单data
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    public void checkSheetAmount(SheetTypeEnum sheetTypeEnum, JSONObject dataList) throws XbbException {
        String msg;
        XbbRefTypeEnum xbbRefTypeEnum = sheetTypeEnum.getXbbRefTypeEnum();
        if (SheetTypeEnum.isWriteOffPre(sheetTypeEnum)) {
            //预收/付款核销读取核销金额
            msg = I18nMessageUtil.getMessage(I18nStringConstant.WRITE_OFF_AMOUNT);
        } else if (SheetTypeEnum.isRed(sheetTypeEnum)) {
            msg = I18nMessageUtil.getMessage(I18nStringConstant.RED_AMOUNT);
        } else if (Objects.equals(xbbRefTypeEnum, XbbRefTypeEnum.PAY_SHEET)) {
            msg = I18nMessageUtil.getMessage(I18nStringConstant.PAY_AMOUNT);
        } else {
            msg = I18nMessageUtil.getMessage(I18nStringConstant.PAYMENT_AMOUNT);
        }
        Double paymentSheetAmount = FundHelp.getSheetAmountBySheetType(sheetTypeEnum, dataList);
        if (paymentSheetAmount <= BasicConstant.ZERO) {
            throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208034.getCode(), format(PaymentErrorCodeEnum.API_ERROR_208034.getMsg(), msg));
        }
        //检查归属人
        checkBelong(sheetTypeEnum, dataList);
    }

    /**
     * 校验回/付款单归属人
     * @param sheetTypeEnum 回/付款单类型
     * @param dataList 回/付款单data
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void checkBelong(SheetTypeEnum sheetTypeEnum, JSONObject dataList) throws XbbException {
        if (SheetTypeEnum.noBelong(sheetTypeEnum)) {
            return;
        }
        JSONArray amountDetail = dataList.getJSONArray(PaasConstant.AMOUNTDETAIL);
        if (amountDetail == null) {
            return;
        }
        //外部归属人必须只能是明细内有金额的归属人，且要排重
        String attrBelongId = Objects.equals(XbbRefTypeEnum.PAY_SHEET, sheetTypeEnum.getXbbRefTypeEnum()) ? PaySheetEnum.BELONG_ID.getAttr() : PaymentSheetEnum.BELONG_ID.getAttr();
        for(Object obj : amountDetail){
            JSONObject jsonObject = (JSONObject)obj;
            //处理归属人
            List<Object> signUserIds = ProSaveHelp.getIdList(jsonObject.getJSONArray(attrBelongId));
            //防止无归属人时，前端传[null]过来
            signUserIds.remove(null);
            if (signUserIds.size() == 0) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NO_BELONG_AMOUNT_DETAIL);
            } else if (signUserIds.size() > 1) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208047, format(PaymentErrorCodeEnum.API_ERROR_208047.getMsg(), sheetTypeEnum.getXbbRefTypeEnum().getName()));
            }
        }
    }

    /**
     * 处理回款单明细内的id和name，塞入相应集合
     * @param jsonObject 明细对象，未保存入库时，明细内关联的字段格式为[{"id": 1, "name": "dd"}]
     * @param attr 关联字段
     * @param detailIds 拼装所有明细的id数组
     * @param detailNames 拼装所有明细的名称数组
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void handleDetailIdName(JSONObject jsonObject, String attr, List<Long> detailIds, List<String> detailNames) throws XbbException {
        JSONArray linkArr = getJsonArrFromFormData(jsonObject, attr);
        if (linkArr == null || linkArr.isEmpty()) {
            return;
        }
        JSONObject linkObj = linkArr.getJSONObject(0);
        //明细内各个字段对应的数组内只有一条（为了给名称排重，所以判断detailIds不包含该id）
        Long id = linkObj.getLongValue(BasicConstant.ID);
        boolean flag = id != null && id != 0L && !detailIds.contains(id);
        if(flag){
            detailIds.add(id);
            String name = linkObj.getString(BasicConstant.NAME);
            detailNames.add(name);
        }
    }

    /**
     * 处理回/付款单明细内的id和name，塞入相应集合
     * @param jsonObject 明细对象
     * @param attr 关联字段
     * @param linkedAttr 关联隐藏字段
     * @param detailIds 拼装所有明细的id数组
     * @param detailNames 拼装所有明细的名称数组
     * @param idToAmount id和金额的对应关系map
     * @param ids 明细内数组的id集合
     * @param amount 明细内金额
     * @throws XbbException
     * @author zcp
     * @date 19/11/21 021 20:09
     * @update 19/11/21 021 20:09
     * @since v1.0
     * @version v1.0
     */
    private void handleDetailIdName(JSONObject jsonObject, String attr, String linkedAttr, List<Long> detailIds, List<String> detailNames, Map<Long, Double> idToAmount, Set<Long> ids, Double amount) throws XbbException {
        List<Long> idList = FastJsonHelper.getJsonArrOrDefaultFromFormData(jsonObject, attr, new JSONArray()).toJavaList(Long.class);
        if (CollectionsUtil.isEmpty(idList)) {
            return;
        }
        jsonObject.put(attr, idList);
        //明细内各个字段对应的数组内只有一条（为了给名称排重，所以判断detailIds不包含该id）
        Long id = idList.get(0);
        boolean flag = id != null && id != 0L && !detailIds.contains(id);
        if(flag){
            detailIds.add(id);
            JSONArray nameArr = FastJsonHelper.getJsonArrFromFormData(jsonObject, linkedAttr);
            detailNames.add(nameArr.getString(0));
            ids.add(id);
        }
        //求金额时，要把金额汇总，如n条明细都是挂到同一个合同下，则需要把所有明细金额汇总得到该合同的回/付款额
        Double value = Arith.add(idToAmount.getOrDefault(id, 0D), amount);
        idToAmount.put(id, value);
    }

    /**
     * 回/付款单公用的save处理部分：校验明细金额，退货id处理等
     * @param validateDataDTO 数据对象
     * @param data 数据data
     * @param sheetTypeEnum 回/付款单类型总枚举
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    public void sheetBeforeSave(ValidateDataDTO validateDataDTO, JSONObject data, SheetTypeEnum sheetTypeEnum) throws XbbException {
        //校验回/付款单金额不能为0（明细内金额不用校验为0）
        boolean checkAmountFlag = (validateDataDTO.getNonCheckAmount() == null || !validateDataDTO.getNonCheckAmount()) && Objects.equals(validateDataDTO.getDataId(), null) || Objects.equals(validateDataDTO.getDataId(), BasicConstant.ZERO_LONG)
                || (Objects.equals(validateDataDTO.getIsImport(),BasicConstant.ONE) && Objects.equals(validateDataDTO.getIsCover(),BasicConstant.ZERO));
        if (checkAmountFlag) {
            checkSheetAmount(sheetTypeEnum, data);
        }
        SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = validateDataDTO.getSaasNeedRedundantAttrPoJo();
        if (saasNeedRedundantAttrPojo != null) {
            if (saasNeedRedundantAttrPojo.getRefundId() != null) {
                data.put(PaasConstant.REFUND_ID, saasNeedRedundantAttrPojo.getRefundId());
            }
            if (saasNeedRedundantAttrPojo.getReturnedPurchaseId() != null) {
                data.put(PaasConstant.RETURNED_PURCHASE_ID, saasNeedRedundantAttrPojo.getReturnedPurchaseId());
            }
        }
    }

    /**
     * 处理回/付款单的明细：当小于等于1条时，不需要处理；大于1条，则把子的合同
     * @param sheetAmount 回/付款单总金额
     * @param sheetTypeEnum 回/付款单类型
     * @param sheetAttrPojo 回/付款单的字段attr pojo
     * @param dataList 父回/付款单数据data
     * @param amountDetails 明细数组
     * @param allAmount 总金额
     * @param contractIdToAmount 合同id-合同已收金额（采购合同id-采购合同已收金额）
     * @param paymentIdToAmount 回/付款计划id-回/付款计划已收金额
     * @param contractIds （采购）合同id集合
     * @param paymentIds 回/付款计划id集合
     * @return java.util.List<com.alibaba.fastjson.JSONObject>
     * @throws XbbException
     * @author zcp
     * @date 19/11/21 021 20:55
     * @update 19/11/21 021 20:55
     * @since v1.0
     * @version v1.0
     */
    public List<JSONObject> handleAmountDetail(SaasFormSaveDTO saasFormSaveDTO, Double sheetAmount, SheetTypeEnum sheetTypeEnum, SheetAttrPojo sheetAttrPojo, JSONObject dataList, JSONArray amountDetails, double allAmount, Map<Long, Double> contractIdToAmount, Map<Long, Double> paymentIdToAmount, Set<Long> contractIds, Set<Long> paymentIds) throws XbbException {
        dataList = fundHelp.formatAmountWriteOff(null, sheetTypeEnum, sheetAttrPojo, dataList);
        ValidateDataDTO validateDataDTO = new ValidateDataDTO();
        BeanUtil.copyProperties(saasFormSaveDTO, validateDataDTO);
        /*
         把回/付款单本身的金额处理掉（置为负数、以及处理回/付款金额、核销金额）
         非明细，则要根据回/付款单类型取金额值：预收款核销使用的是核销金额
         */
        SaveFormatHelp.dealLabelData(dataList, validateDataDTO.getExplainMap());
        Integer distributorMark = validateDataDTO.getDistributorMark();
        //处理经销商支付方式
        String payMethod = handlePayMethod4Distributor(validateDataDTO.getPlatform(), dataList, sheetTypeEnum.getCode(), distributorMark);
        List<JSONObject> sonPaymentSheetDataList = new ArrayList<>();
        if (Objects.nonNull(amountDetails)) {
            for (Object item : amountDetails) {
                JSONObject jsonObject;
                if ( item instanceof HashMap) {
                    jsonObject = new JSONObject((HashMap)item);
                } else {
                    jsonObject = (JSONObject) item;
                }
                SaveFormatHelp.dealLabelData(jsonObject, validateDataDTO.getExplainMap());
            }
        }
        //如果明细只有一条，则只有父本身
        if (amountDetails == null || amountDetails.size() <= 1) {
            //处理归属人
            JSONArray signUserArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, sheetAttrPojo.getAttrBelongId(), new JSONArray());
            //防止无归属人时，前端传[null]过来
            signUserArr.remove(null);
            //没有明细时，则把父本身的关联数据置入相应容器，且限制归属人只能一个
            handleIdAmount4NoDetail(dataList, sheetAttrPojo.getAttrCon(), sheetAmount, contractIdToAmount, contractIds);
            handleIdAmount4NoDetail(dataList, sheetAttrPojo.getAttrPlan(), sheetAmount, paymentIdToAmount, paymentIds);
        } else {
            //明细内有金额的合同、回/付款计划、归属人
            List<Long> detailContractIds = new ArrayList<>();
            List<String> detailContractNos = new ArrayList<>();
            List<Long> detailPaymentIds = new ArrayList<>();
            List<String> detailPaymentNos = new ArrayList<>();
            //外部归属人必须只能是明细内有金额的归属人，且要排重
            Set<Object> detailSignPerson = new HashSet<>();
            validateDataDTO.setBusinessType(sheetTypeEnum.getBusinessType());
            validateDataDTO.setNonCheckAmount(true);
            boolean payPlanSheetFlag = Objects.equals(XbbRefTypeEnum.PAY_SHEET, sheetTypeEnum.getXbbRefTypeEnum()) ? true : false;
            for(Object obj : amountDetails){
                JSONObject jsonObject;
                if (obj instanceof HashMap) {
                    jsonObject = new JSONObject((HashMap)obj);
                } else {
                    jsonObject = (JSONObject) obj;
                }
                Double amount = jsonObject.getDouble(sheetAttrPojo.getAttrAmount());
                if(amount != null && amount != 0D) {
                    validateDataDTO.setData(jsonObject);
                    ProSaveHelp.analyticalData(validateDataDTO);
                    //处理关联客户、合同、回/付款计划、红冲回/付款单id
                    if (payPlanSheetFlag) {
                        payPlanSheetAnalyticalService.beforeSaveSkipValidate(validateDataDTO);
                    } else {
                        paymentSheetAnalyticalService.beforeSaveSkipValidate(validateDataDTO);
                    }
                    //处理归属人
                    List<Object> signUserIds = ProSaveHelp.getIdList(jsonObject.getJSONArray(sheetAttrPojo.getAttrBelongId()));
                    //防止无归属人时，前端传[null]过来
                    signUserIds.remove(null);
                    jsonObject.put(sheetAttrPojo.getAttrBelongId(), signUserIds);
                    detailSignPerson.addAll(signUserIds);
                    allAmount = Arith.add(allAmount, amount);
                    /*
                     把明细的金额处理掉（置为负数、以及处理回/付款金额、核销金额）
                     前端传入的明细，不区分回/付款单类型，恒用的num_1，因此此处传入回/付款单的AMOUNT.getAttr()
                     */
                    jsonObject = fundHelp.formatAmountWriteOff(amount, sheetTypeEnum, sheetAttrPojo, jsonObject);
                    //处理合同，拼到父回/付款的detailContractIds、detailContractNos上
                    handleDetailIdName(jsonObject, sheetAttrPojo.getAttrCon(), sheetAttrPojo.getAttrConLink(), detailContractIds, detailContractNos, contractIdToAmount, contractIds, amount);
                    //处理回/付款，拼到父回/付款的detailPaymentIds、detailPaymentNos上
                    handleDetailIdName(jsonObject, sheetAttrPojo.getAttrPlan(), sheetAttrPojo.getAttrPlanLink(), detailPaymentIds, detailPaymentNos, paymentIdToAmount, paymentIds, amount);
                    //处理子回款单的支付方式
                    handlePayMethod4Distributor4SonSheet(jsonObject, distributorMark, payMethod);
                    sonPaymentSheetDataList.add(jsonObject);
                }
            }
            dataList.put(sheetAttrPojo.getAttrCon(), detailContractIds);
            dataList.put(sheetAttrPojo.getAttrConLink(), detailContractNos);
            dataList.put(sheetAttrPojo.getAttrPlan(), detailPaymentIds);
            dataList.put(sheetAttrPojo.getAttrPlanLink(), detailPaymentNos);
            dataList.put(sheetAttrPojo.getAttrBelongId(), detailSignPerson);
        }
        return sonPaymentSheetDataList;
    }

    /**
     * 标签字段处理
     * @param data
     * @param explainMap
     * @throws XbbException
     */
    public void dealLabelData(JSONObject data,  Map<String, FieldAttrEntity> explainMap) throws XbbException {
        // 标签处理
        SaveFormatHelp.dealLabelData(data, explainMap);
    }

    /**
     * 返回labelId数组
     * 返回可能为null，获取之后需要进行非null判断
     *
     * @param data 表单数据
     * @param attr 要获取数据的key值
     * @throws XbbException 类型转换失败异常
     * @author chaoxiong.lei
     * @date 14:09 2019/1/23
     * @since v1.0
     **/
    public JSONArray getStringLableData(JSONObject data, String attr) throws XbbException {
        return SaveFormatHelp.getStringLableData(data, attr);
    }


    /**
     * 经销商类型回款单，厂商端操作需后端自动赋值（经销商类型且支付方式为空时才赋值）
     *                 代客操作：已核销，预收款
     *                 预收款账户：预收款核销，红冲预收款核销（退到余额）
     *                 线下打款：红冲预收款核销（原Pro的），红冲预收款余额
     *                 另外，红冲已核销与原单一致（关联新建时处理好）
     * @param platform 来源
     * @param data 数据data
     * @param sheetType 回款单类型
     * @param distributorMark 经销商标识
     * @return java.lang.String
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    public String handlePayMethod4Distributor(String platform, JSONObject data, String sheetType, Integer distributorMark) {
        //经销商端platform为INTERNAL，经销商类型回款单，且不是经销商端调用
        boolean flag = Objects.equals(distributorMark, DistributorMarkEnum.DISTRIBUTOR.getCode()) && !Objects.equals(platform, PlatFormEnum.INTERNAL.getValue());
        String payMethod = data.getString(PaymentSheetDistributorEnum.PAY_METHOD.getAttr());
        if (flag && StringUtil.isEmpty(payMethod)) {
            payMethod = SheetTypeEnum.getDefaultPayMethod4Distributor(sheetType);
            data.put(PaymentSheetDistributorEnum.PAY_METHOD.getAttr(), payMethod);
            return payMethod;
        }
        return payMethod;
    }

    /**
     * 处理没有明细的情况：把父回/付款单内关联的数据置入相应容器内，以方便后续更新关联业务的数据（已收回/付款等）
     * @param data 回/付款单data
     * @param attr 字段名
     * @param sheetAmount 回/付款金额
     * @param idToAmount id和金额的对应关系map
     * @param ids 明细内数组的id集合
     * @throws XbbException
     * @author zcp
     * @date 19/12/4 004 16:24
     * @update 19/12/4 004 16:24
     * @since v1.0
     * @version v1.0
     */
    private void handleIdAmount4NoDetail(JSONObject data, String attr, Double sheetAmount, Map<Long, Double> idToAmount, Set<Long> ids) throws XbbException {
        List<Long> idList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, attr, new JSONArray()).toJavaList(Long.class);
        if (idList.size() > BasicConstant.ONE) {
            //无明细，则最多只能一个合同、一个回/付款计划
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NO_AMOUNT_DETAIL);
        }
        if (idList.size() > 0) {
            Long cid = idList.get(0);
            ids.add(cid);
            Double value = idToAmount.getOrDefault(cid, BasicConstant.ZERO_DOUBLE);
            value = Arith.add(value, sheetAmount);
            idToAmount.put(cid, value);
            data.put(attr, idList);
        }
    }

    /**
     * 经销商类型回款单，厂商端操作需后端自动赋值（经销商类型且支付方式为空时才赋值）
     *                 代客操作：已核销，预收款
     *                 预收款账户：预收款核销，红冲预收款核销（退到余额）
     *                 线下打款：红冲预收款核销（原Pro的），红冲预收款余额
     *                 另外，红冲已核销与原单一致（关联新建时处理好）
     * @param data 数据data
     * @param distributorMark 经销商标识
     * @param payMethod 支付方式
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private void handlePayMethod4Distributor4SonSheet(JSONObject data, Integer distributorMark, String payMethod) {
        if (Objects.equals(distributorMark, DistributorMarkEnum.DISTRIBUTOR.getCode()) && StringUtil.isNotEmpty(payMethod)) {
            data.put(PaymentSheetDistributorEnum.PAY_METHOD.getAttr(), payMethod);
        }
    }

    /**
     * 校验金额明细
     * @param sheetAmount 回/付款单总金额
     * @param sheetTypeEnum 回/付款单类型
     * @param sheetAttrPojo 回/付款单的字段attr pojo
     * @param dataList 父回/付款单数据data
     * @param amountDetails 明细数组
     * @param allAmount 总金额
     * @param contractIdToAmount 合同id-合同已收金额（采购合同id-采购合同已收金额）
     * @param paymentIdToAmount 回/付款计划id-回/付款计划已收金额
     * @param contractIds （采购）合同id集合
     * @param paymentIds 回/付款计划id集合
     * @return java.util.List<com.alibaba.fastjson.JSONObject>
     * @throws XbbException
     * @author zcp
     * @date 19/11/21 021 20:55
     * @update 19/11/21 021 20:55
     * @since v1.0
     * @version v1.0
     */
    public void checkAmountDetail(ValidateDataDTO validateDataDTO, Double sheetAmount, SheetTypeEnum sheetTypeEnum, SheetAttrPojo sheetAttrPojo, JSONObject dataList, JSONArray amountDetails, double allAmount, Map<Long, Double> contractIdToAmount, Map<Long, Double> paymentIdToAmount, Set<Long> contractIds, Set<Long> paymentIds) throws XbbException {
        boolean payPlanSheetFlag = Objects.equals(XbbRefTypeEnum.PAY_SHEET, sheetTypeEnum.getXbbRefTypeEnum()) ? true : false;
        if (amountDetails == null || amountDetails.size() <= 1) {
            //处理归属人
            JSONArray signUserArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(dataList, sheetAttrPojo.getAttrBelongId(), new JSONArray());
            //防止无归属人时，前端传[null]过来
            signUserArr.remove(null);
            if (signUserArr.size() == 0) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NO_BELONG_AMOUNT_DETAIL);
            } else if (signUserArr.size() > 1) {
                throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208047, format(PaymentErrorCodeEnum.API_ERROR_208047.getMsg(), sheetTypeEnum.getXbbRefTypeEnum().getName()));
            }
            //没有明细时，则把父本身的关联数据置入相应容器，且限制归属人只能一个
            handleIdAmount4NoDetail(dataList, sheetAttrPojo.getAttrCon(), sheetAmount, contractIdToAmount, contractIds);
            handleIdAmount4NoDetail(dataList, sheetAttrPojo.getAttrPlan(), sheetAmount, paymentIdToAmount, paymentIds);
        } else {
            List<Long> detailContractIds = new ArrayList<>();
            List<String> detailContractNos = new ArrayList<>();
            List<Long> detailPaymentIds = new ArrayList<>();
            List<String> detailPaymentNos = new ArrayList<>();
            for (Object obj : amountDetails) {
                JSONObject jsonObject = (JSONObject)obj;
                //这整个方法只是校验，不能对原对象进行改变
                JSONObject validateJson = (JSONObject) jsonObject.clone();
                if (payPlanSheetFlag) {
                    formatLinkBusiness4Save(validateJson, PaySheetEnum.LINK_PURCHASE.getAttr(), PaySheetEnum.PURCHASE_LINK_TEXT.getAttr(), PaySheetEnum.LINK_PURCHASE.getFieldType());
                    formatLinkBusiness4Save(validateJson, PaySheetEnum.PAY_PLAN.getAttr(), PaySheetEnum.PAY_PLAN_LINK_TEXT.getAttr(), PaySheetEnum.PAY_PLAN.getFieldType());
                } else {
                    formatLinkBusiness4Save(validateJson, PaymentSheetEnum.CONTRACT.getAttr(), PaymentSheetEnum.CONTRACT_LINK_TEXT.getAttr(), PaymentSheetEnum.CONTRACT.getFieldType());
                    formatLinkBusiness4Save(validateJson, PaymentSheetEnum.PAYMENT.getAttr(), PaymentSheetEnum.PAYMENT_LINK_TEXT.getAttr(), PaymentSheetEnum.PAYMENT.getFieldType());
                }
                Double amount = validateJson.getDouble(sheetAttrPojo.getAttrAmount());
                if (amount != null && amount != 0D) {
                    List<Object> signUserIds = ProSaveHelp.getIdList(validateJson.getJSONArray(sheetAttrPojo.getAttrBelongId()));
                    //防止无归属人时，前端传[null]过来
                    signUserIds.remove(null);
                    if (signUserIds.size() == 0) {
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NO_BELONG_AMOUNT_DETAIL);
                    } else if (signUserIds.size() > 1) {
                        throw new XbbException(PaymentErrorCodeEnum.API_ERROR_208047, format(PaymentErrorCodeEnum.API_ERROR_208047.getMsg(), sheetTypeEnum.getXbbRefTypeEnum().getName()));
                    }
                    allAmount = Arith.add(allAmount, amount);
                    /*
                     把明细的金额处理掉（置为负数、以及处理回/付款金额、核销金额）
                     前端传入的明细，不区分回/付款单类型，恒用的num_1，因此此处传入回/付款单的AMOUNT.getAttr()
                     */
                    validateJson = fundHelp.formatAmountWriteOff(amount, sheetTypeEnum, sheetAttrPojo, validateJson);
                    //处理合同，拼到父回/付款的detailContractIds、detailContractNos上
                    handleDetailIdName(validateJson, sheetAttrPojo.getAttrCon(), sheetAttrPojo.getAttrConLink(), detailContractIds, detailContractNos, contractIdToAmount, contractIds, amount);
                    //处理回/付款，拼到父回/付款的detailPaymentIds、detailPaymentNos上
                    handleDetailIdName(validateJson, sheetAttrPojo.getAttrPlan(), sheetAttrPojo.getAttrPlanLink(), detailPaymentIds, detailPaymentNos, paymentIdToAmount, paymentIds, amount);
                }
            }
            //判断明细总金额和外面输入的是否相等
            if (!Objects.equals(allAmount, sheetAmount)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.NOT_EQUAL_AMOUNT_DETAIL);
            }
        }

    }

    /**
     * 关联业务单选
     * 将前端传入的json对象格式转换成两个字段
     *
     * @param data       前端传回的data数据
     * @param attr       要格式化的字段attr
     * @param linkedAttr 格式化字段对应的隐藏字段
     * @throws XbbException 参数格式错误异常
     * @author chaoxiong.lei
     * @date 15:38 2019/1/21
     * @since v1.0
     **/
    public void formatLinkBusiness4Save(JSONObject data, String attr, String linkedAttr, Integer fieldType) throws XbbException {
        if (data == null || attr == null || linkedAttr == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
        }
        try {
            JSONArray jsonArray = data.getJSONArray(attr);
            if (jsonArray != null && !jsonArray.isEmpty()) {
                List<String> idList = new ArrayList<>();
                List<String> nameList = new ArrayList<>();
                for (int i = 0; i < jsonArray.size(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    idList.add(jsonObject.getString(StringConstant.SAAS_LINK_BUSINESS_ID));
                    nameList.add(jsonObject.getString(StringConstant.SAAS_LINK_BUSINESS_NAME));
                }
                if (Objects.equals(FieldTypeEnum.LINK_BUSINESS_MULTI.getType(), fieldType)) {
                    // 鲁江：下拉多选不要用逗号或者竖线分割，存成array
                    data.put(attr,idList);
                    data.put(linkedAttr, nameList);
                } else {
                    if(idList.size() > BasicConstant.ZERO) {
                        data.put(attr, idList.get(BasicConstant.ZERO));
                    }else {
                        data.put(attr, null);
                    }
                    if(idList.size() > BasicConstant.ZERO) {
                        data.put(linkedAttr, nameList.get(BasicConstant.ZERO));
                    }else {
                        data.put(linkedAttr, null);
                    }
                }
            } else {
                data.put(attr, null);
                data.put(linkedAttr, null);
            }
        } catch (Exception e) {
            //   throw new XbbException(SystemErrorCodeEnum.API_ERROR_100015);
        }
    }

    /**
     * 回、付款单更新时明细的标签处理
     */
    public void dealLabelDataForSheet(JSONArray amountDetail,ValidateDataDTO validateDataDTO) throws XbbException{
        for (Object amountDetailObj : amountDetail){
            JSONObject amountDetailJson = (JSONObject) amountDetailObj;
            SaveFormatHelp.dealLabelData(amountDetailJson,validateDataDTO.getExplainMap());
        }
    }
}
